package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
	"github.com/zachary/tbox/internal/config"
	"github.com/zachary/tbox/internal/svc"
	"github.com/zachary/tbox/internal/util"
	"github.com/zachary/tbox/internal/web"
	"github.com/zachary/tbox/internal/web/global"
	"github.com/zeromicro/go-zero/core/color"
	"github.com/zeromicro/go-zero/core/conf"
	"github.com/zeromicro/go-zero/rest"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func newRunCommand() *cobra.Command {
	var server *rest.Server
	runC := &cobra.Command{
		Use:     "start",
		Short:   "Run server",
		Long:    "Start http server!",
		Example: "tbox start -f etc/tbox-api.yaml",
		PreRun: func(cmd *cobra.Command, args []string) {
			server = preRun(cmd)
		},
		Run: func(cmd *cobra.Command, args []string) {
			runServer(server)
		},
	}
	// 指定运行参数：-f 指定配置文件
	runC.Flags().StringP("file", "f", "etc/tbox-api.yaml", "config path")
	return runC
}

func preRun(cmd *cobra.Command) (server *rest.Server) {
	var c config.Config
	configFile := cmd.Flag("file").Value.String()
	fmt.Println(color.WithColor("loading config file:", color.FgGreen), color.WithColor(configFile, color.FgMagenta))
	conf.MustLoad(configFile, &c)
	server = rest.MustNewServer(c.RestConf, rest.WithUnauthorizedCallback(global.UnauthorizedCallback))
	ctx := svc.NewServiceContext(c)
	web.RegisterHandlers(server, ctx)
	return
}

func runServer(server *rest.Server) {
	// 等待中断信号以优雅地关闭服务器
	// kill (no param) default send syscanll.SIGTERM
	// kill -2 is syscall.SIGINT
	// kill -9 is syscall. SIGKILL but can"t be catch, so don't need add it
	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

	//开启新的goroutine启动
	go func() {
		defer func() {
			if err := recover(); err != nil {
				fmt.Println(color.WithColor("Server start failed:", color.FgRed), err)
				time.Sleep(time.Millisecond * 200)
				quit <- syscall.SIGTERM
			}
		}()
		// 添加中间件
		svc.AddMiddleware(server)
		// 初始化并启动监听
		server.StartWithOpts(
			// 初始化上下文
			func(svr *http.Server) {
				svc.Init(svr)
			}, startPrint)
	}()

	<-quit
	fmt.Printf("%s Shutdown Server ... \r\n", util.NowDateTimeStr())
	log.Println("Server exiting")
	server.Stop()
}

func startPrint(svr *http.Server) {
	c := svc.GetServiceContext().Config
	fmt.Printf(color.WithColor("Starting server at %s:%d...\n", color.FgGreen), c.Host, c.Port)
	time.Sleep(time.Millisecond * 500)
	fmt.Println(color.WithColor("Server run at:", color.FgGreen))
	fmt.Printf("-  %s:   http://localhost:%d/ \r\n", color.WithColor("Local", color.BgGreen), c.Port)
	fmt.Printf("-  %s: http://%s:%d/ \r\n", color.WithColor("Network", color.BgGreen), util.GetLocalHost(), c.Port)
	fmt.Printf("%s Enter Control + C Shutdown Server \r\n", util.NowDateTimeStr())
}
